#include "PinDebouncer.h"

#if (ARDUINO <= 22)
 #include <WProgram.h>
#else
 #include <Arduino.h>
#endif

PinDebouncer
    ::PinDebouncer(
    	unsigned char pinNumber,
    	unsigned int minimumUsBetweenPinStateSamples,
    	unsigned char* pinStateFilterArray,
    	unsigned char pinStateFilterArraySize) :
    		mPinNumber(pinNumber),
    		mPinStateFilterArray(pinStateFilterArray),
    		mPinStateFilterArraySize(pinStateFilterArraySize),
    		mMinimumUsBetweenPinStateSamples(minimumUsBetweenPinStateSamples)
{
	mLastPinStateSampleAtUs = micros();
}

void PinDebouncer
	::Service(void)
{
	if (
		(mPinStateFilterArraySize > 0) &&
		(mPinStateFilterArray != 0x0))
	{
		unsigned long _currentSampleTimeUs = micros();
		unsigned long _durationSinceLastSample = 0;
		
		// Wrapped around?
		if (_currentSampleTimeUs <= mLastPinStateSampleAtUs)
		{
			_durationSinceLastSample = 
				((unsigned long)(0xFFFFFFFF) - mLastPinStateSampleAtUs) +
				_currentSampleTimeUs;
		}
		else
		{
			_durationSinceLastSample = 
				_currentSampleTimeUs - mLastPinStateSampleAtUs;
		}
		
		if (_durationSinceLastSample > mMinimumUsBetweenPinStateSamples)
		{
			for (unsigned int i = (mPinStateFilterArraySize - 1); i > 0; i--)
			{
				mPinStateFilterArray[i] =
					mPinStateFilterArray[i - 1];
			}
			
			mPinStateFilterArray[0] = digitalRead(mPinNumber);
		}
	}
}

unsigned char PinDebouncer
	::GetPinState(void)
{
	unsigned char _highSamples = 0;
	unsigned char _retVal = LOW;
	
	for (unsigned int i = 0; i < mPinStateFilterArraySize; i++)
	{
		_highSamples += (mPinStateFilterArray[i] == HIGH) ? 1 : 0;
	}
	
	if (_highSamples >= (mPinStateFilterArraySize >> 1))
	{
		_retVal = HIGH;
	}
	
	return _retVal;
}
